package com.googlecode.messwertepi.services;

import com.google.inject.Inject;
import com.google.inject.Provider;
import com.googlecode.messwertepi.configuration.Configuration;
import com.googlecode.messwertepi.util.IoUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.print.*;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.Copies;
import javax.print.event.PrintJobAdapter;
import javax.print.event.PrintJobEvent;
import java.io.*;
import java.util.List;

/**
 * Created by eike on 15.07.14.
 */
public class DefaultPrinterService implements PrinterService {
    final private static Logger LOG = LoggerFactory.getLogger(DefaultPrinterService.class);

    private Provider<PrintService> printServiceProvider;
    private Configuration configuration;

    @Inject
    public DefaultPrinterService(Provider<PrintService> printServiceProvider, Configuration configuration) {
        this.printServiceProvider = printServiceProvider;
        this.configuration = configuration;
    }

    @Override
    public String getPrinterName() {
        PrintService printer = printServiceProvider.get();
        return printer.getName();
    }

    @Override
    public void print(List<String> rows) {
        PrintService printer = printServiceProvider.get();

        FileInputStream in = null;
        try {
            in = new FileInputStream(new File("/home/eike/test.txt"));

            // set the print request attributes
            PrintRequestAttributeSet printAttribute = new HashPrintRequestAttributeSet();
            printAttribute.add(new Copies(1));

            // create the document
            DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
            Doc doc = new SimpleDoc(in, flavor, null);

            // create and execute the print job
            DocPrintJob job = printer.createPrintJob();
            PrintJobWatcher jobWatcher = new PrintJobWatcher(job);
            job.print(doc, printAttribute);
            jobWatcher.waitForDone();
        } catch (IOException ioe) {
            LOG.error("Failed to print data", ioe);
        } catch (PrintException pe) {
            LOG.error("Failed to print data", pe);
        } finally {
            IoUtil.safeClose(in);
        }


        // send FF to eject the page
        //InputStream ff = new ByteArrayInputStream("\f".getBytes());
        //Doc docff = new SimpleDoc(ff, flavor, null);
        //DocPrintJob jobff = printer.createPrintJob();
        //pjw = new PrintJobWatcher(jobff);
        //jobff.print(docff, null);
        //pjw.waitForDone();
    }

    /**
     * The PrintJobWatcher class is used to block, until the print job is done.
     */
    private static class PrintJobWatcher {
        boolean done = false;

        public PrintJobWatcher(DocPrintJob job) {
            job.addPrintJobListener(new PrintJobAdapter() {
                @Override
                public void printJobCanceled(PrintJobEvent pje) {
                    allDone();
                }

                @Override
                public void printJobCompleted(PrintJobEvent pje) {
                    allDone();
                }

                @Override
                public void printJobFailed(PrintJobEvent pje) {
                    allDone();
                }

                @Override
                public void printJobNoMoreEvents(PrintJobEvent pje) {
                    allDone();
                }

                private void allDone() {
                    synchronized (this) {
                        done = true;
                        this.notify();
                    }
                }
            });
        }

        public synchronized void waitForDone() {
            try {
                while (!done) {
                    wait();
                }
            } catch (InterruptedException e) {
            }
        }
    }
}
